#include "intend/IceSailing.h"

DepotMang::DepotMang(){
    try{
        QString Tonic = "/";
        QStringList LocalInfo = QProcess::systemEnvironment();
        QStringList FilterItem = LocalInfo.filter(QRegularExpression("USERNAME=(.*)"));
        if (!FilterItem.isEmpty())
        {
            LCUSERNAME = FilterItem[0].split("=")[1];
            DBNAME = LCUSERNAME + ".db";
            DEPOTFD = Nlwingsing::jigsawPath(SYSPATH + Tonic + LCUSERNAME);
        }
        else
        {
            DBNAME = "shipping.db";
            DEPOTFD = Nlwingsing::jigsawPath(SYSPATH + Tonic + "shipping");
        }
        DBPATH = Nlwingsing::jigsawPath(DEPOTFD + Tonic + DATA_WAREHOUSE + Tonic + DBNAME);
        LOGPATH = Nlwingsing::jigsawPath(DEPOTFD + Tonic + MAINLOGDIRECTORY + Tonic + LOGNAME);
        RLPATH = Nlwingsing::jigsawPath(DEPOTFD + Tonic + RLNAME);
        QRCODE_FDPATH = Nlwingsing::jigsawPath(DEPOTFD + Tonic + QRCODE_FDNAME);
        SERIAL_FDPATH = Nlwingsing::jigsawPath(DEPOTFD + Tonic + SERIAL_FDNAME);
        RESOURCE_MSPATH = Nlwingsing::jigsawPath(DEPOTFD + Tonic + MEDIA_FDNAME+ Tonic + MEDIAMS_FDNAME);
        RESOURCE_MVPATH = Nlwingsing::jigsawPath(DEPOTFD + Tonic + MEDIA_FDNAME+ Tonic + MEDIAMV_FDNAME);
        SCROPED_DIR_MAKE(DBPATH, true);
        SCROPED_DIR_MAKE(LOGPATH, true);
        SCROPED_DIR_MAKE(RLPATH, true);

        SCROPED_DIR_MAKE(DEPOTFD, false);
        SCROPED_DIR_MAKE(QRCODE_FDPATH, false);
        SCROPED_DIR_MAKE(SERIAL_FDPATH, false);
        SCROPED_DIR_MAKE(RESOURCE_MSPATH, false);
        SCROPED_DIR_MAKE(RESOURCE_MVPATH, false);

        DATABASE = new QSqlDatabase();
        *DATABASE = DATABASE->addDatabase("QSQLITE");
        DATABASE->setDatabaseName(DBPATH);
        DATABASE->open();
        QUERY = new QSqlQuery(*DATABASE);

        QSysInfo info;
        RUNNINGENV.append("running env:");
        RUNNINGENV.append("\tkernel-type: " + info.kernelType());
        RUNNINGENV.append("\tkernel-id: " + info.machineUniqueId());
        RUNNINGENV.append("\tkernel-version: " + info.kernelVersion());
        RUNNINGENV.append("\tkernel-build: " + info.buildCpuArchitecture());
        RUNNINGENV.append("\tkernel-api: " + info.buildAbi());
        RUNNINGENV.append("\tlocal-user: " + LCUSERNAME);

        RLUPDTINFP.insert("DBNAME", DBNAME);
        RLUPDTINFP.insert("DBPATH", DBPATH);
        RLUPDTINFP.insert("DBSTAT", "True");
        RLUPDTINFP.insert("MD5STAT", "True");

        __LOG__();
        QSettings globalsetting("GlobalTool", "RGLRLS");
        globalsetting.setValue("LOGPATH", LOGPATH);
        globalsetting.setValue("LOGWRITE", definfc.BoolAssert(RGLRLSMAP["LOGCFG"]["LOGWRITE"]));
        globalsetting.setValue("LOGPRINT", definfc.BoolAssert(RGLRLSMAP["LOGCFG"]["LOGPRINT"]));
        globalsetting.setValue("LOGLEVEL", RGLRLSMAP["LOGCFG"]["LOGLEVEL[1-5]"].toInt());
        globalsetting.sync();

        __REGKEY__(_INIFILE_, RLREG, _INI_REGISTER_);
        __SQL_CREATE__();
        __INIT__(false, true);
        __Qss__();

    }
    catch(QException &Error){
        diary(Error.what(), Diary::Error);
    }
}


void DepotMang::__SQL_CREATE__(){

    QUERY->exec("CREATE TABLE mutex("
                "id INTEGER primary key AUTOINCREMENT,"
                "mutex char(35),"
                "key char(50));");

    QUERY->exec("CREATE table user_datum("
                "ac_id char(16) PRIMARY KEY,"
                "ac_name char(200),"
                "ac_key char(16),"
                "ac_head text,"
                "recall bool,"
                "relogin bool,"
                "final bool,"
                "might bool);");

    QUERY->exec("CREATE table user_favora_datum("
                "ac_mdfvr char(200) PRIMARY KEY,"
                "ac_id char(16),"
                "coverp char(455),"
                "lock char(200));");

    QUERY->exec("CREATE table user_heahs_datum("
                "ac_headp char(500) PRIMARY KEY,"
                "ac_id char(16),"
                "head_clipsize char(20),"
                "head_cliprect char(30),"
                "apply bool);");

    QUERY->exec("CREATE table media_datum("
                "mdrs_name char(255) PRIMARY KEY,"
                "mdrs_artist char(50),"
                "mdrs_path char(155),"
                "mdrs_suffix char(6),"
                "mdrs_size char(10),"
                "mdrs_duration char(10),"
                "mdrs_bitrate char(10),"
                "mdrs_cover char(510),"
                "mdrs_state bool,"
                "prd_time char(20),"
                "alter_time char(20),"
                "nrply_time char(20),"
                "mdrs_lyric text,"
                "owner char);");

    QUERY->exec("CREATE table net_driver("
                "mutex char primary key,"
                "name char default null,"
                "path char default null,"
                "verision char default null,"
                "create char default null)");

    QUERY->exec("CREATE table serial("
                "sp_name defult 'None' char primary key, "
                "baudrate char,"
                "dataplace char,"
                "stopplace char,"
                "checkplace  char,"
                "scontrol char,"
                "ordercode char,"
                "ordernike char,"
                "portname char,"
                "highlight char,"
                "searchinfo char,"
                "apply bool)");


    QUERY->exec("CREATE TABLE qrcode("
                "id INTEGER primary key AUTOINCREMENT,"
                "data char(35),"
                "key char(50),"
                "route char,"
                "alias char(50));");

    diary("sql table create be ok", Diary::Success)
}


void DepotMang::__CRYPT_MD5__(){
    try{
        QByteArray Mydata;
        Mydata.append(DBKEY.toLocal8Bit());
        Mydata.append(FORMATDATE.toLocal8Bit());
        QString RealKey;
        QString RealValue;
        QByteArray HasMd5 = QCryptographicHash::hash(Mydata, QCryptographicHash::Md5);
        QString Value = (HasMd5.toHex().toStdString().c_str());
        QString Key = Mydata.toBase64().toStdString().c_str();
        QMap<QString, QList<QString>> MutexData = definfc.SuperQuery(DATABASE, "mutex");
        if (MutexData["mutex"].isEmpty()){
            QString paserSql = "insert into mutex(mutex, key) values('%1', '%2')";
            if (QUERY->exec(paserSql.arg(Value, Key)))
            {
                diary(QString("md5->[key: %1, value: %2] insert successful").arg(RealKey, RealValue), Diary::Success)
            }
            else
            {
                diary(QString("md5->[key: %1, value: %2] insert fail").arg(RealKey, RealValue), Diary::Error)
            }
            RealKey = Key;
            RealValue = Value;
        } else {
            if (MutexData["mutex"][0].size() != Value.size() ||
                MutexData["key"][0].size() != Key.size()) {
                QString paserSql = "UPDATE mutex set mutex = '%1', key = '%2' WHERE id=%3;";
                if (QUERY->exec(paserSql.arg(Value, Key, MutexData["ID"][0])))
                {
                    diary(QString("md5->[key: %1, value: %2] update successful").arg(RealKey, RealValue), Diary::Success)
                }
                else
                {
                    diary(QString("md5->[key: %1, value: %2] update fail").arg(RealKey, RealValue), Diary::Error)
                }
                RealKey = Key;
                RealValue = Value;
            } else {
                RealKey = MutexData["key"][0];
                RealValue = MutexData["mutex"][0];
                diary(QString("md5->[key: %1, value: %2] from sqldata").arg(RealKey, RealValue), Diary::Debug)
            }
        }
        LCDBMAP["DBKV"] = qMakePair(RealKey, RealValue);

    } catch( QException::exception &Error ){
        diary(Error.what(), Diary::Error)
    }
}


void DepotMang::__CFG_WRITE__(QString PATH, QString TGL){
    Reader::d_writer(PATH, TGL.toLocal8Bit(), QIODevice::WriteOnly);
}


void DepotMang::__CFG_READ__(){
    QMap<QString, QMap<QString, QString>> Content = Reader::g_inifile(RLPATH, RLREG);
    RGLRLSMAP.insert(Content);
}


void DepotMang::__CFG_UPDT__(QMap<QString, QString> DPDTMAP, bool IsReset){
    QString RplRowContent;
    QString rulesContent;
    QStringList Keys = DPDTMAP.keys();
    QStringList Values = DPDTMAP.values();
    QString ExpectChar = "%1=%2";
    //#=====区分是否重置
    if ( IsReset ){
        rulesContent = _INIFILE_;
    } else {
        rulesContent = QString::fromLocal8Bit(Reader::g_reader(RLPATH));
    }
    //#=====循环需要更新value的字典
    for (int keyrow = 0; keyrow < Keys.size(); keyrow++){
        QString PrepareRe = "%1\\s*=\\s*.*";
        QRegularExpression reg(PrepareRe.arg(Keys[keyrow]));
        QRegularExpressionMatch Match = reg.match(rulesContent);
        QStringList RplRowList = Match.capturedTexts();
        RplRowContent = RplRowList.last();
        int AntIndex = RplRowContent.lastIndexOf(";");
        if ( AntIndex != -1 ){
            RplRowContent = RplRowContent.mid(0, AntIndex);
        }
        int EqualIndex = RplRowContent.indexOf("=", 0);
        if ( EqualIndex != -1 ){
            QString key = RplRowContent.mid(0, EqualIndex);
            QString value = RplRowContent.mid(EqualIndex + 1, -1);
            if ( key == Keys[keyrow] &&
                value == Values[keyrow]) {
                continue;
            } else {
                rulesContent = rulesContent.replace(RplRowContent,
                                                    ExpectChar.arg(
                                                    Keys[keyrow], Values[keyrow]));
            }
        }
    }
    if (!rulesContent.isEmpty()) __CFG_WRITE__(RLPATH, rulesContent);
    diary("config load ok, rglmap write ok", Diary::Debug)
    QStringList UpKeys = DPDTMAP.keys();
    QStringList UpValues = DPDTMAP.values();
    for (int n = 0; n < UpKeys.size(); n++){diary(UpKeys[n] + ", " + Nlwingsing::jigsawPath(UpValues[n], false, true), Diary::Debug)}
}


void DepotMang::__REGKEY__(QString Souce, QString Reg, QStringList &Vessel){
    foreach(QString IniRow, Souce.split("\n")) {
        QStringList Match = QRegularExpression(Reg).match(IniRow).capturedTexts();
        if (!Match.isEmpty() && Match.size()>1) Vessel << Match[1];
    }
    diary(QString("rglkey load ok, keys: [%1]").arg(Vessel.join(", ")), Diary::Success)
}


void DepotMang::__Qss__(){
    foreach (QString qss, QssList){
        QSSMAP.insert(Reader::g_qsstyle(qss, QSSREG));
        QResource::registerResource(qss);
        diary(QString("qss file: %1, load ok").arg(qss), Diary::Debug)
    }
}


void DepotMang::__INIT__(bool IsReset, bool skipread){
    __CRYPT_MD5__();
    if (!skipread) __CFG_READ__(); // log 在该函数之前运行，执行了read函数，此时应该避免重复读取
    if (RGLRLSMAP["ALL"]["TEXT"].isEmpty()){
        RLUPDTINFP.insert("MD5", LCDBMAP["DBKV"].second);
        __CFG_WRITE__(RLPATH, _INIFILE_);
        CTCHECK = true;
        MD5CHECK = true;
        diary("rules text is empty, write init now", Diary::Debug)
    } else {
        int INIRGST = 0;
        int INICMKEY = 0;
        int RGSTCOUNT = _INI_REGISTER_.size();
        QStringList RGLRLKEYS = RGLRLSMAP.keys();
        foreach(QString RGIT, _INI_REGISTER_) {
            if (RGLRLKEYS.contains(RGIT)){
                INIRGST++;
            } else {
                _INI_LOSSKEY_ << RGIT;
            }
            if (!RGLRLSMAP[RGIT].isEmpty()) INICMKEY++;
        }

        if (INIRGST == RGSTCOUNT && INICMKEY == RGSTCOUNT){
            CTCHECK = true;
        } else CTCHECK = false;
        if (RGLRLSMAP["MD5"].isEmpty() ||
            RGLRLSMAP["MD5"]["MD5"].isEmpty() ||
            RGLRLSMAP["MD5"]["MD5"] != LCDBMAP["DBKV"].second){
            MD5CHECK = false;
        }else MD5CHECK = true;
    }
    int SplitIndex = _HEADERS_.indexOf(":");

    __CFG_UPDT__(RLUPDTINFP, IsReset);
    __CFG_READ__();
    RGLRLSMAP["PATH"].insert("SYSPATH", SYSPATH);
    RGLRLSMAP["PATH"].insert("SYSFD", DEPOTFD);
    RGLRLSMAP["PATH"].insert("LOGPATH", LOGPATH);
    RGLRLSMAP["PATH"].insert("DBPATH", DBPATH);
    RGLRLSMAP["PATH"].insert("QRCODEPATH", QRCODE_FDPATH);
    RGLRLSMAP["PATH"].insert("SERIALPATH", SERIAL_FDPATH);
    RGLRLSMAP["PATH"].insert("RLPATH", RLPATH);
    RGLRLSMAP["PATH"].insert("MVPATH", RESOURCE_MVPATH);
    RGLRLSMAP["PATH"].insert("MSPATH", RESOURCE_MSPATH);
    RGLRLSMAP["BKHD"].insert(_HEADERS_.mid(0, SplitIndex).trimmed(),
                             _HEADERS_.mid(SplitIndex, -1).trimmed());

}


void DepotMang::__LOG__(){
    __CFG_READ__();
    int LOGSTOREDAY = RGLRLSMAP["LOGCFG"]["LOGSTOREDAY"].toInt();
    int LOGMAXSIZE = RGLRLSMAP["LOGCFG"]["LOGMAXSIZE"].toInt();
    QStringList result;
    SCROPED_LOCAL_FIND(DEPOTFD, "diary-", "log", MatchingMode_Simple, result);
    if (!result.empty())
    {
        QMap<qint64, QString> relationMap;
        QFileInfo fileinfo;
        foreach(QString logFile, result)
        {
            fileinfo = QFileInfo(logFile);
            QFile File(logFile);
            int fileSize = File.size() / (1024 * 1024);
            QDateTime filebirthTime = fileinfo.birthTime().toLocalTime();
            qint64 OtherNess = filebirthTime.msecsTo(CURDATE)  / 1000;
            if (OtherNess < (60 * 60 * 60 * LOGSTOREDAY) &&
                fileSize < LOGMAXSIZE && logFile != LOGPATH)
            {
                relationMap[OtherNess] = logFile;
                diary2("valid log file", Nlwingsing::jigsawPath(logFile, true, true), Diary::Debug)
            } else diary2("past log file: ", logFile, Diary::Warning)
            diary6("file:", fileinfo.baseName(), "variant otherness: ", OtherNess, "size: ", fileSize, Diary::Debug);
        }
        if (!relationMap.isEmpty())
        {
            int minvalue = definfc.Min(relationMap.keys());
            LOGPATH = relationMap[minvalue];
            diary4("willing log file: ", Nlwingsing::jigsawPath(LOGPATH, true, true), " sz: ", minvalue, Diary::Debug)
        }
    }
    RLUPDTINFP.insert("LOGNAME", LOGPATH.split(QRegularExpression("[\\\\|/]")).last());
    RLUPDTINFP.insert("LOGPATH", LOGPATH);

}

